﻿#region Usings

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using log4net;
using Quest.PowerGUI;
using Quest.PowerGUI.Engine.Shell;
using Quest.PowerGUI.Engine.Shell.Host;
using Quest.PowerGUI.ScriptEditor;
using Quest.PowerGUI.ScriptEditor.Shared;
using Quest.PowerGUI.ScriptEditor.Shared.Debugger;

#endregion

namespace PowerGui.AddOn.Impl
{
    /// <summary>
    /// Utility class for loading the PowerGUI settings.
    /// </summary>
    [Export]
    public class ConfigLoader
    {
        #region Fields

        private static readonly object Locker = new object();
        private static readonly ILog Log = LogManager.GetLogger(typeof (ConfigLoader));

        private static bool loaded;

        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the shell.
        /// </summary>
        /// <value>The shell.</value>
        public IShellPart Shell { get; private set; }

        /// <summary>
        /// Gets or sets the settings manager.
        /// </summary>
        /// <value>The settings manager.</value>
        public SettingsManager SettingsManager { get; private set; }

        [Import]
        public PowerShellDebugger Debugger { get; set; }

        #endregion

        #region Methods
        public void Callback(HostCallbackParameter param)
        {
            Trace.WriteLine(String.Format("ConfigLoader: MainHostCallback: Type: {0} Message: {1}", param.Type, param.Message));
        }

        /// <summary>
        /// Loads the settings.
        /// </summary>
        public void LoadSettings()
        {
            Log.Debug("Entering LoadSettings().");

            if (loaded)
            {
                return;
            }

            try
            {
                Logger s_CurrentLogger = null;
                string path = System.IO.Path.Combine(ProductFolder.UserDataFolder, ProductFolder.SpecialFile.EditorConfig);
                string strAlternatePath = System.IO.Path.Combine(ProductFolder.UserDataFolder, ProductFolder.SpecialFile.OldEditorConfig);
                if (!XMLSettingsManager.FileExists(path, strAlternatePath))
                {
                    Log.InfoFormat("PowerGUI config file [{0}] does not exist.", path);
                    XMLSettingsManager.CreateEmptyConfigFile(path, false);
                }
                using (SettingsManager manager = new XMLSettingsManager())
                {
                    using (SettingsManager manager2 = new XMLSettingsManager(path))
                    {
                        SettingsManager.Current = manager2;

                        lock (Locker)
                        {
                            try
                            {
                                manager2.Load();
                            }
                            catch
                            {
                                XMLSettingsManager.CreateEmptyConfigFile(path, true);
                                manager2.Load();
                            }

                            EditorSettings.Instance.Load(manager2);

                            manager2.DialogSettings.LogOptions.LogLevel = SourceLevels.Information;
                            manager2.DialogSettings.LogOptions.EraseLogOnExit = false;

                            s_CurrentLogger = new Logger(ProductFolder.SpecialFile.EditorLog);
                            s_CurrentLogger.SourceLevel = SourceLevels.Information;
                            s_CurrentLogger.EraseLogOnExit = false;
                            manager2.Logger = s_CurrentLogger;
                            
                            PowerGUISettings.InitSettings(manager);
                            SettingsManager.ConsoleSettings = new ConsoleSettings(manager);
                            SettingsManager.ConsoleSettings.Settings.Logger = manager2.Logger;
                            try
                            {
                                PrepareConfigFolder.PrepareConfig();
                            }
                            catch (Exception ex)
                            {
                                Log.Error("Failed to prepare config.", ex);
                            }

                            SettingsManager = manager2;
                        }
                    }
                }
            }
            catch (Exception exception2)
            {
                Log.Error("Failed to setup configuration.", exception2);
                Trace.WriteLine(exception2.Message);
                throw;
            }

            try
            {
                Shell = Debugger.Debugger.GetCurrentMonadShell(RunScriptMode.None,
                                                         () =>
                                                         ConfigUtils.GetLoadedSnapins(
                                                             SettingsManager.ConsoleSettings.Settings));

                if (Shell != null)
                {
                    var param = new ScriptParameters
                    {
                        NewThread = false,
                        Nested = false
                    };
                    IEnumerable<SnapinInfo> modulesSnapins = Shell.GetModulesSnapins(false, param);
                    ConfigUtils.PutLoadedSnapins(SettingsManager.ConsoleSettings.Settings, modulesSnapins);
                    ConfigUtils.PutAdditionalSnapins(SettingsManager.ConsoleSettings.Settings, modulesSnapins.Where(m => m.Type == SnapinType.Snapin));
                    SettingsManager.ConsoleSettings.Settings.SavePart(SettingsManager.ID_SHELLPART);

                    try
                    {
                        CmdLetImporter.ImportCommands(Shell, SettingsManager.ConsoleSettings.Settings);
                        PSSyntaxEditorControl.InitializeProviderISense(Shell, Debugger.Debugger);
                    }
                    catch (Exception ex)
                    {
                        Log.Error("Failed to import commands", ex);
                    }
                }

                loaded = true;
            }
            catch (Exception ex)
            {
                Log.Error("Failed to load config settings.", ex);
            }
            

            Log.Debug("Leaving ConfigLoader.");
        } 
        #endregion
    }
}
